﻿using System.Collections.Specialized;
using System.Web.Mvc;
using SharpArch.Core;
using System;
using System.Collections.Generic;
using SharpArch.Core.CommonValidator;

namespace SharpArch.Web.CommonValidator
{
    public class MvcValidationAdapter
    {
        public static ModelStateDictionary TransferValidationMessagesTo(
            ModelStateDictionary modelStateDictionary,
            IEnumerable<IValidationResult> validationResults) {

            return TransferValidationMessagesTo(null, modelStateDictionary, validationResults);
        }
    
        /// <summary>
        /// This acts as a more "manual" alternative to moving validation errors to the 
        /// <see cref="ModelStateDictionary" /> if you care to bypass the use of 
        /// <see cref="ValidatableModelBinder" />.  This typically wouldn't be used in conjunction
        /// with <see cref="ValidatableModelBinder" /> but as an alternative to it.
        /// </summary>
        /// <param name="keyBase">If supplied, will be used as the model state prefix
        /// instead of the class name</param>
        public static ModelStateDictionary TransferValidationMessagesTo(
            string keyBase, ModelStateDictionary modelStateDictionary, 
            IEnumerable<IValidationResult> validationResults) {

            Check.Require(modelStateDictionary != null, "modelStateDictionary may not be null");
            Check.Require(validationResults != null, "invalidValues may not be null");

            foreach (IValidationResult validationResult in validationResults) {
                Check.Require(validationResult.ClassContext != null,
                    "validationResult.ClassContext may not be null");

                string key = (keyBase ?? validationResult.ClassContext.Name) +
                    (!string.IsNullOrEmpty(validationResult.PropertyName)
                        ? "." + validationResult.PropertyName
                        : "");

                var message = SplitUpperCaseToString(validationResult.PropertyName) + " " + validationResult.Message;
                
                modelStateDictionary.AddModelError(key, message);
                modelStateDictionary.SetModelValue(key, new ValueProviderResult(null, null, null));
            }

            return modelStateDictionary;
        }

        public static string SplitUpperCaseToString(string source)
        {
            return string.Join(" ", SplitUpperCase(source));
        }

        public static string[] SplitUpperCase(string source)
        {
            if (source == null)
                return new string[] { }; //Return empty array.

            if (source.Length == 0)
                return new string[] { "" };

            StringCollection words = new StringCollection();
            int wordStartIndex = 0;

            char[] letters = source.ToCharArray();
            // Skip the first letter. we don't care what case it is.
            for (int i = 1; i < letters.Length; i++)
            {
                if (char.IsUpper(letters[i]))
                {
                    //Grab everything before the current index.
                    words.Add(new String(letters, wordStartIndex, i - wordStartIndex));
                    wordStartIndex = i;
                }
            }

            //We need to have the last word.
            words.Add(new String(letters, wordStartIndex, letters.Length - wordStartIndex));

            //Copy to a string array.
            string[] wordArray = new string[words.Count];
            words.CopyTo(wordArray, 0);
            return wordArray;
        }
    }
}
